package com.example.demo.util.httpclient;

import org.apache.http.client.HttpClient;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.LayeredConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLInitializationException;
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;

import javax.net.ssl.SSLContext;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;

/**
 * HttpExecutorBuilder
 *
 * @author hao.chen
 * @date 2023/6/3 19:54
 */
public class HttpExecutorBuilder {

    // 每个路由的最大连接数
    private int maxPerRoute = 100;
    // 最大连接数
    private int maxTotal = 200;
    // 是否重试
    private boolean retry = false;
    // 重试次数
    private int retryCount = 3;

    public static HttpExecutorBuilder custom() {
        return new HttpExecutorBuilder();
    }

    public HttpExecutorBuilder maxPerRoute(int maxPerRoute) {
        this.maxPerRoute = maxPerRoute;
        return this;
    }

    public HttpExecutorBuilder maxTotal(int maxTotal) {
        this.maxTotal = maxTotal;
        return this;
    }

    public HttpExecutorBuilder enableRetry() {
        this.retry = true;
        return this;
    }

    public HttpExecutorBuilder retryCount(int retryCount) {
        this.retry = true;
        this.retryCount = retryCount;
        return this;
    }

    public HttpExecutor build() {
        HttpClientBuilder clientBuilder = HttpClientBuilder.create();

        LayeredConnectionSocketFactory ssl = null;
        try {
            ssl = SSLConnectionSocketFactory.getSystemSocketFactory();
        } catch (final SSLInitializationException ex) {
            final SSLContext sslcontext;
            try {
                sslcontext = SSLContext.getInstance(SSLConnectionSocketFactory.TLS);
                sslcontext.init(null, null, null);
                ssl = new SSLConnectionSocketFactory(sslcontext);
            } catch (final SecurityException ignore) {
            } catch (final KeyManagementException ignore) {
            } catch (final NoSuchAlgorithmException ignore) {
            }
        }

        final Registry<ConnectionSocketFactory> sfr = RegistryBuilder.<ConnectionSocketFactory>create()
                .register("http", PlainConnectionSocketFactory.getSocketFactory())
                .register("https", ssl != null ? ssl : SSLConnectionSocketFactory.getSocketFactory())
                .build();

        // 连接池
        PoolingHttpClientConnectionManager connPoolManager = new PoolingHttpClientConnectionManager(sfr);
        connPoolManager.setDefaultMaxPerRoute(maxPerRoute);
        connPoolManager.setMaxTotal(maxTotal);
        connPoolManager.setValidateAfterInactivity(1000);
        clientBuilder.setConnectionManager(connPoolManager);

        // 重试策略
        if (this.retry) {
            HttpRequestRetryHandler retryHandler = new DefaultHttpRequestRetryHandler(retryCount, false);
            clientBuilder.setRetryHandler(retryHandler);
        }

        clientBuilder.setConnectionManagerShared(true);
        HttpClient httpClient = clientBuilder.build();

        return new HttpExecutor(httpClient);
    }
}
